<template>
  <a-form ref="formRef" class="form-contianer" :model="model" :layout="layout">
    <div
      class="form-item"
      :class="'form-item__' + layout + ' ' + item.type + ' ' + (item.col || '')"
      v-for="(item, index) in list"
      :key="index"
      v-bind="item"
      @click.stop="select(item.index || '')"
    >
      <label
        for=""
        v-if="item.label"
        v-html="item.label"
        :style="{ width: item.labelWidth || '68px' }"
      ></label>
      <a-form-item :name="item.field" :rules="item.rules || []">
        <i
          class="del"
          v-if="item.type === 'icon'"
          :class="item.icon"
          @click="() => remove(item, index)"
        ></i>
        <div
          v-else
          :class="
            item.dragTarget
              ? 'form-item__content section'
              : 'form-item__content'
          "
          :data-set-attr="JSON.stringify(item)"
        >
          <Ele
            :attrs="item"
            @elChange="change"
            @autoSelected="autoSelected"
            v-model:checkedKeys="model[item.field]"
            v-model:value="model[item.field]"
            v-model:checked="model[item.field]"
            v-model:file-list="model[item.field]"
          >
            <template v-if="item.slotName" #[item.slotName]>
              <slot :name="item.slotName"></slot>
            </template>
          </Ele>
        </div>
      </a-form-item>
    </div>
  </a-form>
</template>

<script setup>
const props = defineProps({
  allowDelete: {
    type: Boolean,
    default: false,
  },
  layout: {
    type: String,
    default: () => {
      return "horizontal";
    },
  },
  data: {
    type: [Array, Function],
    default: () => {
      return [];
    },
  },
});

const emit = defineEmits();

const formRef = ref();

const list = ref([]);

const transformObj = (val, arr, key) => {
  if (val) {
    const v = val instanceof Array ? val : val.split(",");
    arr.forEach((a, i) => {
      modalV[a] = v.length ? v[i] : "";
    });
    delete modalV[key];
  }
};

/**
 * 定义一个名为model的响应式对象，用于存储数据。
 * @type {Object}
 */
const model = reactive({});
const modalV = reactive({});

/**
 * 初始化model对象的属性，基于传入的props数据。
 * 此函数通过遍历list.value中的每个项，将它们的属性值赋给model对象，
 * 以此来预设model的状态。
 */
const initModel = () => {
  try {
    // 确保所有依赖变量已定义
    if (
      !list.value ||
      typeof list.value !== "object" ||
      Object.keys(list.value).length === 0 ||
      !modalV ||
      typeof modalV !== "object" ||
      !model ||
      typeof model !== "object" ||
      typeof transformObj !== "function"
    ) {
      console.error("依赖变量未定义或为空");
      return;
    }

    const processUploadField = (value, imgPrefix) => {
      const v = Array.isArray(value) ? value : value ? value.split(",") : [];
      return v.map((r) => ({
        name: "", // 默认值，避免未定义
        status: "done",
        url: `${imgPrefix || ""}${r}`,
      }));
    };

    const updateModelAndTransform = (field, value, arr2obj) => {
      modalV[field] = value;
      model[field] = value;

      if (arr2obj) {
        transformObj(value, arr2obj, field);
      }
    };

    for (const a of list.value) {
      if (a.type && a.field) {
        let value = a.value;

        if (a.type === "Upload") {
          const processedValue = processUploadField(value, a.imgPrefix);
          updateModelAndTransform(a.field, processedValue, a.arr2obj);
        } else {
          updateModelAndTransform(a.field, value, a.arr2obj);
        }
      } else {
        console.warn(`无效的字段配置: ${JSON.stringify(a)}`);
      }
    }

    emit("change", modalV);
  } catch (error) {
    if (error instanceof TypeError) {
      console.error("类型错误:", error.message);
    } else {
      console.error("初始化模型时发生错误:", error);
    }
  }
};

watch(
  () => props.data,
  (val) => {
    if (val instanceof Function) {
      val().then((res) => {
        if (res.code === rescf.codeVal) {
          list.value = res.data;
        }
        initModel();
      });
    } else if (val instanceof Array) {
      list.value = val;
      initModel();
    }
  },
  {
    immediate: true,
    deep: true,
  },
);

/**
 * 定义一个 `validate` 函数，用于触发表单的验证。
 *
 * 该函数没有参数。
 *
 * @returns {Promise<boolean>} 返回一个 Promise，该 Promise 解析为一个布尔值，表示表单验证是否通过。
 *
 * 注意：这里利用了 Vue 的Composition API 中 `ref` 的 `value` 属性来访问底层的 DOM 元素或组件实例。
 * 使用这种方式，我们可以直接调用表单组件实例的方法，比如验证方法 (`validate`)。
 */
const validate = () => {
  return formRef.value.validate();
};

const clearModelValue = () => {
  for (const a of list.value) {
    model[a.field] = a.value instanceof Array ? [] : "";
    modalV[a.field] = a.value instanceof Array ? [] : "";
  }
};

/**
 * 重置表单字段。
 *
 * 该函数用于重置由 formRef 引用的表单的所有字段值，
 * 使其恢复到初始状态，清空用户输入的数据。
 *
 * 调用此函数可以快速清理表单状态，无需手动设置每个字段的值。
 */
const resetForm = () => {
  formRef.value.resetFields();
  clearModelValue();
};

/**
 * 将给定对象的值赋给模型对象。
 * 此函数用于同步外部传入的对象值到内部模型，以便模型反映最新的数据状态。
 * @param {Object} val - 包含需要更新的属性及其值的对象。
 */
const setForm = (val) => {
  // 遍历传入对象的所有属性，将它们的值赋给模型对象
  for (const key in model) {
    if (!model.hasOwnProperty(key)) continue;

    const filteredItems = list.value.filter((item) => item.field === key);
    const item = filteredItems[0];

    if (item) {
      if (item.type === "Upload") {
        if (Array.isArray(val[key])) {
          model[key] = val[key].map((name) => ({
            name,
            status: "done",
            url: `${item.imgPrefix}${name}`,
          }));
        } else {
          model[key] = [];
        }
      } else if (item.arr2obj) {
        if (Array.isArray(item.arr2obj)) {
          item.arr2obj.forEach((field) => {
            modalV[field] = val[field];
          });
          delete modalV[key];
        }
      } else if (item.type === "Cascader" && item.label2obj) {
        if (Array.isArray(item.label2obj)) {
          item.label2obj.forEach((field) => {
            modalV[field] = val[field];
          });
        }
      } else if (item.arr2str && Array.isArray(val[key])) {
        modalV[key] = val[key].join(",");
      } else if (
        item.arrPop &&
        Array.isArray(val[key]) &&
        val[key].length > 0
      ) {
        modalV[key] = val[key][val[key].length - 1];
      } else {
        model[key] = val[key];
        modalV[key] = val[key];
      }
    } else {
      model[key] = val[key];
      modalV[key] = val[key];
    }
  }

  console.log(modalV, val, "00000000");

  // 触发change事件，携带更新后的模型数据
  emit("change", modalV);
};

/**
 * 监听模型数据的变化并触发自定义事件。
 * 此函数旨在提供一种更新模型数据并通知监听者数据变化的方式。
 * @param {Object} obj - 包含字段和值的对象，用于更新模型数据。
 * @param {string} obj.field - 模型中要更新的字段名。
 * @param {*} obj.value - 更新字段的新值。
 * @emits change - 当模型数据更新时触发，传递更新后的模型作为参数。
 */
const change = (obj, val) => {
  // 更新模型数据
  model[obj.field] = obj.value;
  modalV[obj.field] = obj.value;
  const ll = list.value.filter((a) => a.field === obj.field);
  const idx = list.value.findIndex((a) => a.field === obj.field);
  if (ll.length) {
    if (ll[0].type === "Upload") {
      model[obj.field] = obj.value.map((a) => {
        return {
          name: a,
          status: "done",
          url: `${ll[0].imgPrefix}${a}`,
        };
      });
    }
    if (ll[0].arr2obj) {
      ll[0].arr2obj.forEach((a, i) => {
        modalV[a] = obj.value?.length ? obj.value[i] : "";
      });
    }
    if (ll[0].type === "Cascader" && ll[0].label2obj) {
      let m = {};
      if (val) {
        m = val.map((r) => r[ll[0].optionsProps.label || "label"]);
        ll[0].label2obj.forEach((k, i) => {
          modalV[k] = m[i];
        });
      }
    }
    if (ll[0].arr2str) {
      modalV[obj.field] = obj.value.join(",");
    }

    if (ll[0].arrPop) {
      modalV[obj.field] = obj.value[obj.value.length - 1];
    }
  }

  // console.log("sss", listCopy, '======', list.value);

  // 触发change事件，携带更新后的模型数据
  emit(
    "change",
    modalV,
    {
      field: obj.field,
      idx: idx,
      val: obj.value,
    },
    val,
  );
};

const remove = (item, i) => {
  try {
    // 确保 i 和 item.size 是有效的
    if (!list.value || i < 0 || i >= list.value.length || item.size <= 0) {
      console.warn("Invalid parameters for remove function");
      return;
    }

    // 修正 splice 参数，确保删除正确的元素数量
    const startIndex = Math.max(0, i - item.size + 1);
    const deleteCount = i - startIndex + 1;
    list.value.splice(startIndex, deleteCount);

    // 安全地获取正则表达式匹配结果
    const ak = item.field.match(/\-[a-zA-Z0-9-_]+$/);
    if (ak && ak[0]) {
      const keySuffix = ak[0];
      for (const key in modalV) {
        if (key.includes(keySuffix)) {
          delete modalV[key];
        }
      }
    }

    // 触发 change 事件
    emit("change", modalV);

    // initModel();
  } catch (error) {
    console.error("Error in remove function:", error);
  }
};
/**
 * 向列表中添加表单数据
 * 如果列表不是数组，则初始化为空数组
 * 然后将新数据与现有列表合并
 * @param {any} val - 要添加到列表中的表单数据
 */
const addForm = (val, gx) => {
  if (!Array.isArray(list.value)) {
    list.value = [];
  }
  list.value = list.value.concat(val);
  console.log(list.value, gx, "000000000000000");
  if (gx) {
    initModel();
  }
  return list.value;
};

/**
 * 获取表单数据
 *
 * 该函数返回一个列表，其中包含当前组件实例中定义的`list`属性的值
 * 主要用途是提供一种访问组件内部状态的方法，而不直接操作组件实例
 *
 * @returns {Array} 返回组件实例中定义的list属性的值
 */
const getForm = () => {
  return list.value;
};

/**
 * 自动选择下拉框选项
 * 根据传入的对象字段与列表中的字段匹配
 * 如果找到匹配项，则设置模型值为选项列表的第一个值
 * 并触发 change 和 search 事件
 * @param {Object} obj - 包含字段信息的对象
 * @param {Array} optionList - 下拉框的选项列表
 */
const autoSelected = (obj, optionList) => {
  const ll = list.value.filter((a) => a.field === obj.field);
  if (ll.length) {
    model[ll[0].field] = optionList[0].value;
    modalV[ll[0].field] = optionList[0].value;
    emit("change", modalV);
    emit("search", {
      label: "搜索",
      type: "primary",
      key: "search",
    });
  }
};

/**
 * 选择项函数
 * 该函数用于处理当一个项被选择时的逻辑
 * @param {any} index - 被选择的项
 */
const select = (index) => {
  emit("select", index);
};

// 把相关方法暴露给外部使用
defineExpose({
  setForm,
  addForm,
  getForm,
  validate,
  resetForm,
});
</script>
<style lang="scss" scoped>
:deep(.form-item__horizontal) {
  display: flex;
  label {
    text-align: right;
    margin-right: 10px;
    height: 32px;
    line-height: 32px;
  }
  label ~ * {
    flex: 1;
  }
  div:last-child {
    flex: 1;
  }
}
:deep(.form-item__inline) {
  gap: 10px 0;
}
:deep(.form-item__inline) {
  display: flex;
  label {
    text-align: right;
    margin-right: 10px;
    height: 32px;
    line-height: 32px;
  }
  label ~ * {
    width: 200px;
  }
  &.RangePicker .ant-form-item {
    width: 400px;
  }
}
:deep(.form-item__vertical) {
  display: flex;
  label {
    text-align: right;
    margin-right: 10px;
    height: 32px;
    line-height: 32px;
  }
  label ~ * {
    flex: 1;
  }
}

.del {
  color: #ff6e48;
  font-size: 20px;
  padding: 3px 5px;
  cursor: pointer;
}
</style>
